package gbench.sandbox.matlib;

import org.junit.jupiter.api.Test;

import static gbench.common.matlib.MatlibCanvas.println;
import static gbench.common.matlib.algebra.lisp.MyRecord.REC;
import static gbench.common.matlib.algebra.lisp.Node.PACK;
import static gbench.common.matlib.algebra.op.Ops.flat_mapper;
import static gbench.common.matlib.matrix.Matrix.V;
import static gbench.common.matlib.algebra.lisp.IRecord.*;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import gbench.common.matlib.MatlibCanvas.NVec;
import gbench.common.matlib.algebra.lisp.Tuple2;
import gbench.common.matlib.algebra.AlgebraEngine;
import gbench.common.matlib.algebra.op.BinaryOp;
import gbench.common.matlib.algebra.op.Comma;
import gbench.common.matlib.algebra.op.UnaryOp;
import gbench.common.matlib.matrix.Matrix;
import gbench.common.matlib.matrix.MatrixOps;
import gbench.common.matlib.algebra.lisp.IRecord;
import gbench.common.matlib.algebra.lisp.Node;

/**
 * 数据演示2
 * 
 * @author gbench
 *
 */
public class JunitAlgebra2 {
    
    /**
     * 运算处理器
     * 
     * @author gbench
     *
     * @param <X> 左参数类型
     * @param <Y> 右参数类型
     */
    static class Handler<X, Y> extends Tuple2<Class<X>, Class<Y>> {

        /**
         * 
         * @param _1
         * @param _2
         * @param handler
         */
        public Handler(Class<X> _1, Class<Y> _2, BiFunction<X, Y, ?> handler) {
            super(_1, _2);
            this.evaluator = handler;
        }

        /**
         * handler 是否支持 (ltype,rtype)类型的数值运算
         * 
         * @param ltype
         * @param rtype
         * @return
         */
        public boolean supports(final Class<?> ltype, final Class<?> rtype) {
            return this._1.isAssignableFrom(ltype) && this._2.isAssignableFrom(rtype);
        }

        /**
         * 
         * @param args
         * @return
         */
        public boolean supports(final Object[] args) {
            final Class<?>[] types = Stream.of(args)
                    .map(e -> e == null 
                        ? Object.class 
                        : e instanceof Class<?> 
                            ? (Class<?>) e 
                            : e.getClass())
                    .toArray(Class[]::new);

            return this.supports(types[0], types[1]);
        }

        public Object handle(X x, Y y) {
            return evaluator.apply(x, y);
        }

        @SuppressWarnings("unchecked")
        public Object handle(final Object[] args) {
            return this.handle((X) args[0], (Y) args[1]);
        }

        /**
         * 
         * @param <X>
         * @param <Y>
         * @param _1
         * @param _2
         * @param evaluator
         * @return
         */
        public static <X, Y> Handler<X, Y> of(final Class<X> _1, final Class<Y> _2,
                final BiFunction<X, Y, ?> evaluator) {
            return new Handler<>(_1, _2, evaluator);
        }

        private final BiFunction<X, Y, ?> evaluator;
    }
    
    /**
     * 自定义 二元算符：乘法算符 <br>
     * 
     * compose 和 evaluate 连个函数是 进行 自定义算符 必须实现的 函数
     * 
     * @author gbench
     * 
     * @param <T>
     */
    static class Transpose<T> extends UnaryOp<T> {

        public Transpose(final T t) {
            super("t", t);
        }

        @Override
        public Transpose<T> duplicate() {
            return new Transpose<>(this._2._1);
        }
        
        /**
         * compose 和 evaluate 连个函数是 进行 自定义算符 必须实现的 函数 <br>
         * 根据 argsEval 计算的参数 进行 算符求值
         */
        @Override
        public Object evaluate(final Map<String, Object> bindings) {
            final var args = new Object[] {PACK(this._2._1).evaluate(bindings),null};
            final var opt = handlers.stream().filter(e -> e.supports(args)).findFirst();
            
            return opt.map(e -> e.handle(args)).orElse(null);
        }

        /**
         * compose 和 evaluate 连个函数是 进行 自定义算符 必须实现的 函数 <br>
         * 固定返回 自定义函数对象本身 <br>
         */
        @Override
        public <X> Transpose<X> compose(final X x) {
            return new Transpose<>(x);
        }
        
        final static List<Handler<? , ? >>  handlers = Arrays.asList( // 运算的多态注册器
            Handler.of(Matrix.class, Object.class, (left, right) -> left.transpose()), // (NVec,NVec)
            Handler.of(Number[][].class, Object.class, (left, right) -> MatrixOps.transpose(left)), // (NVec,Number),
            Handler.of(NVec.class, Object.class, (left, right) -> MatrixOps.transpose(V(left).toArray())) // (NVec,Number),
        );
    }

    /**
     * 自定义 二元算符：乘法算符 <br>
     * 
     * compose 和 evaluate 连个函数是 进行 自定义算符 必须实现的 函数
     * 
     * @author gbench
     * 
     * @param <T>
     */
    static class Mul<T, U> extends BinaryOp<T, U> {

        public Mul(final T t, U u) {
            super("*", TUP2(t, u));
        }

        @Override
        public Mul<T, U> duplicate() {
            return new Mul<>(this._2._1, this._2._2());
        }
        
        /**
         * compose 和 evaluate 连个函数是 进行 自定义算符 必须实现的 函数 <br>
         * 根据 argsEval 计算的参数 进行 算符求值
         */
        @Override
        public Object evaluate(final Map<String, Object> bindings) {
            final var args = this.argsEval(bindings); // 计算参数
            final var opt = handlers.stream().filter(e -> e.supports(args)).findFirst();
            
            return opt.map(e -> e.handle(args)).orElse(null);
        }

        /**
         * compose 和 evaluate 连个函数是 进行 自定义算符 必须实现的 函数 <br>
         * 固定返回 自定义函数对象本身 <br>
         */
        @Override
        public <X, Y> Mul<X, Y> compose(final X x, final Y y) {
            return new Mul<>(x, y);
        }
        
        final static List<Handler<? , ? >>  handlers = Arrays.asList( // 运算的多态注册器
            Handler.of(NVec.class, NVec.class, (left, right) -> left.mul(right)), // (NVec,NVec)
            Handler.of(NVec.class, Number.class, (left, right) -> left.mul(right)), // (NVec,Number)
            Handler.of(Number.class, NVec.class, (left, right) -> right.mul(left)), // (Number,Nvec)
            Handler.of(NVec.class, String.class, (left, right) -> left.mul(dbl(right))), // (NVec,String)
            Handler.of(String.class, NVec.class, (left, right) -> right.mul(dbl(left))), // (String,Nvec)
            Handler.of(Matrix.class, NVec.class, (left, right) -> { // Matrix to Nvec
                return mmult(dblcorece(left),V(right));
            }), // (Matrix,Nvec)
            Handler.of(NVec.class, Matrix.class, (left, right) -> { // NVec to Matrix
                return mmult(V(left),dblcorece(right));
            }), // (NVec,Matrix)
            Handler.of(Matrix.class, Matrix.class, (left, right) -> { // Matrix to Matrix
                return mmult(dblcorece(left),dblcorece(right));
            }), // (Matrix,Matrix)
            Handler.of(Matrix.class, Object.class, (left, right) -> { // Matrix to Object
                final var c = IRecord.obj2dbl().apply(right);
                return dblcorece(left).fmap(e -> e * c);
            }), // (Matrix,Object)
            Handler.of(Object.class, Matrix.class, (left, right) -> { // Object to Matrix
                final var c = IRecord.obj2dbl().apply(left);
                return dblcorece(right).fmap(e -> e * c);
            }), // (Object,Matrix)
            Handler.of(Object.class, Object.class, (left, right) -> { // (Object,Object)
                final var dbls = Stream.of(left, right).map(obj2dbl()).toArray(Double[]::new);
                return Stream.of(dbls).reduce((a, b) -> a * b).orElse(dbls[0]);
            }));
    }
    
    /**
     * 自定义 二元算符：加法算符 <br>
     * 
     * compose 和 evaluate 连个函数是 进行 自定义算符 必须实现的 函数
     * 
     * @author gbench
     * 
     * @param <T>
     */
    static class Add<T, U> extends BinaryOp<T, U> {

        public Add(final T t, U u) {
            super("+", TUP2(t, u));
        }

        @Override
        public Add<T, U> duplicate() {
            return new Add<>(this._2._1, this._2._2());
        }
        
        /**
         * compose 和 evaluate 连个函数是 进行 自定义算符 必须实现的 函数 <br>
         * 根据 argsEval 计算的参数 进行 算符求值
         */
        @Override
        public Object evaluate(final Map<String, Object> bindings) {
            final var args = this.argsEval(bindings); // 计算参数
            final var opt = handlers.stream().filter(e -> e.supports(args)).findFirst();
            return opt.map(e -> e.handle(args)).orElse(null);
        }

        /**
         * compose 和 evaluate 连个函数是 进行 自定义算符 必须实现的 函数 <br>
         * 固定返回 自定义函数对象本身 <br>
         */
        @Override
        public <X, Y> Add<X, Y> compose(final X x, final Y y) {
            return new Add<>(x, y);
        }
        
        final static List<Handler<? , ? >>  handlers = Arrays.asList( // 运算的多态注册器
            Handler.of(NVec.class, NVec.class, (left, right) -> left.add(right)), // (NVec,NVec)
            Handler.of(NVec.class, Number.class, (left, right) -> left.add(right)), // (NVec,Number)
            Handler.of(Number.class, NVec.class, (left, right) -> right.add(left)), // (Matrix,Nvec)
            Handler.of(NVec.class, String.class, (left, right) -> left.add(dbl(right))), // (NVec,Number)
            Handler.of(String.class, NVec.class, (left, right) -> right.add(dbl(left))), // (Matrix,Nvec)
            Handler.of(Matrix.class, NVec.class, (left, right) -> { // Matrix to Nvec
                return new Matrix<>(MatrixOps.add(dblcorece(left).cells(),V(right).cells()));
            }), // (Matrix,Nvec)
            Handler.of(NVec.class, Matrix.class, (left, right) -> { // NVec to Matrix
                return new Matrix<>(MatrixOps.add(dblcorece(right).cells(),V(left).cells()));
            }), // (NVec,Matrix)
            Handler.of(Matrix.class, Matrix.class, (left, right) -> { // Matrix to Matrix
                return new Matrix<>(MatrixOps.add(dblcorece(right).cells(),dblcorece(left).cells()));
            }), // (Matrix,Matrix)
            Handler.of(Matrix.class, Object.class, (left, right) -> { // Matrix to Object
                final var c = IRecord.obj2dbl().apply(right);
                return new Matrix<>(MatrixOps.add(dblcorece(left).cells(),c));
            }), // (Matrix,Object)
            Handler.of(Object.class, Matrix.class, (left, right) -> { // Object to Matrix
                final var c = IRecord.obj2dbl().apply(left);
                return new Matrix<>(MatrixOps.add(dblcorece(right).cells(),c));
            }), // (Object,Matrix)
            Handler.of(Object.class, Object.class, (left, right) -> { // (Object,Object)
                final var dbls = Stream.of(left, right).map(obj2dbl()).toArray(Double[]::new);
                return Stream.of(dbls).reduce((a, b) -> a + b).orElse(dbls[0]);
            }));
    }
    

    /**
     * 自定义 二元算符： 赋值运算符 <br>
     * 
     * compose 和 evaluate 连个函数是 进行 自定义算符 必须实现的 函数
     * 
     * @author gbench
     * 
     * @param <T>
     */
    static public class Assign<T, U> extends BinaryOp<T, U> {

        public Assign(final T t, U u) {
            super(":", TUP2(t, u));
        }

        @Override
        public Assign<T, U> duplicate() {
            return new Assign<>(this._2._1, this._2._2());
        }

        /**
         * compose 和 evaluate 连个函数是 进行 自定义算符 必须实现的 函数 <br>
         * 根据 argsEval 计算的参数 进行 算符求值
         */
        @Override
        public Object evaluate(final Map<String, Object> bindings) {

            final var key = this._2._1.toString();
            final var value = PACK(this._2._2).evaluate(bindings);
            bindings.put(key, value);
            return value;
        }

        /**
         * compose 和 evaluate 连个函数是 进行 自定义算符 必须实现的 函数 <br>
         * 固定返回 自定义函数对象本身 <br>
         */
        @Override
        public <X, Y> Assign<X, Y> compose(final X x, final Y y) {
            return new Assign<>(x, y);
        }
        
        /**
         * 逗号的优先级是0,让Assign的优先级比逗号稍微大一点,然后比其他的优先级又都小一点
         */
        @Override
        public Number getPriority() {
            return 0.5;
        }

    }

    /**
     * 自定义 二元算符：提取算符 <br>
     * 
     * [(rec,key) 或者 rec [ key 这样的参数模式，提取rec中的key属性 <br>
     * 
     * compose 和 evaluate 连个函数是 进行 自定义算符 必须实现的 函数
     * 
     * 
     * @author gbench
     * 
     * @param <T>
     */
    static class Get<T, U> extends BinaryOp<T, U> {

        public Get(final T t, U u) {
            super("[", TUP2(t, u));
        }

        @Override
        public Get<T, U> duplicate() {
            return new Get<>(this._2._1, this._2._2());
        }

        /**
         * compose 和 evaluate 连个函数是 进行 自定义算符 必须实现的 函数 <br>
         * 根据 argsEval 计算的参数 进行 算符求值
         */
        @Override
        public Object evaluate(final Map<String, Object> bindings) {
            var rec = PACK(this._2._1).evaluate(bindings); // 结算数据主体
            final var key = PACK(this._2._2).getName(); // 键值
            
            if (rec instanceof Map) {
                rec = REC(rec);
            } else if (rec instanceof Number[]) { // if
                rec = NVec.of((Number[]) rec);
            }

            if (rec instanceof IRecord) {
                return ((IRecord) rec).get(key, _k -> bindings.get(_k));
            } else if (rec instanceof NVec) {
                final var _key = bindings.getOrDefault(key, key);
                final var i = IRecord.obj2dbl().apply(_key).intValue();
                return ((NVec) rec).get(i);
            } else {
                return bindings.get(key);
            } // if
            
        }

        /**
         * compose 和 evaluate 连个函数是 进行 自定义算符 必须实现的 函数 <br>
         * 固定返回 自定义函数对象本身 <br>
         */
        @Override
        public <X, Y> Get<X, Y> compose(final X x, final Y y) {
            return new Get<>(x, y);
        }

    }
    
    /**
     * 自定义 二元算符：小于算符 <br>
     * 
     * compose 和 evaluate 连个函数是 进行 自定义算符 必须实现的 函数
     * 
     * @author gbench
     * 
     * @param <T>
     */
    static public class Lt<T, U> extends BinaryOp<T, U> {
    
        public Lt(final T t, U u) {
            super("<", TUP2(t, u));
        }
    
        @Override
        public Lt<T, U> duplicate() {
            return new Lt<>(this._2._1, this._2._2());
        }
    
        /**
         * compose 和 evaluate 连个函数是 进行 自定义算符 必须实现的 函数 <br>
         * 根据 argsEval 计算的参数 进行 算符求值
         */
        @Override
        public Object evaluate(final Map<String, Object> bindings) {
            final var oo = this.argsEval(bindings); // 计算参数
            final var vv = Stream.of(oo).flatMap(flat_mapper).map(e -> PACK(e).evaluate(bindings))
                    .map(IRecord.obj2dbl()).toArray(Double[]::new);
            return vv[0] < vv[1];
        }
    
        /**
         * compose 和 evaluate 连个函数是 进行 自定义算符 必须实现的 函数 <br>
         * 固定返回 自定义函数对象本身 <br>
         */
        @Override
        public <X, Y> Lt<X, Y> compose(final X x, final Y y) {
            return new Lt<>(x, y);
        }
    
    }

    /**
     * 自定义 二元 算符：连接算符 <br>
     * 
     * compose 和 evaluate 连个函数是 进行 自定义算符 必须实现的 函数
     * 
     * @author gbench
     *
     * @param <T>
     * @param <U>
     */
    static class Join<T, U> extends BinaryOp<T, U> {

        public Join(final T t, U u) {
            super(";", TUP2(t, u));
        }

        @Override
        public Join<T, U> duplicate() {
            return new Join<>(this._2._1, this._2._2());
        }

        /**
         * compose 和 evaluate 连个函数是 进行 自定义算符 必须实现的 函数 <br>
         * 根据 argsEval 计算的参数 进行 算符求值
         */
        @Override
        public Object evaluate(final Map<String, Object> bindings) {
            final var nodes = flatten(";", this);

            final var results = nodes.stream().map(e -> {
                return e.evaluate(bindings); // 节点计算
            }).collect(Collectors.toList());

            return results.size() > 0 ? results.get(results.size() - 1) : null;
        }

        /**
         * compose 和 evaluate 连个函数是 进行 自定义算符 必须实现的 函数 <br>
         * 固定返回 自定义函数对象本身 <br>
         */
        @Override
        public <X, Y> Join<X, Y> compose(final X x, final Y y) {
            return new Join<>(x, y);
        }
        
        /**
         * 逗号的优先级是0,让Assign的优先级比逗号稍微大一点,然后比其他的优先级又都小一点
         */
        @Override
        public Number getPriority() {
            return 0.4;
        }

    }

    /**
     * 多元算符 采用一元算符来实现
     * 
     * 自定义 一元算符：for 循环 三元运算符 <br>
     * for(init,condition,increment) <br> 
     * for是指令结构信息，需要 与 后面的 分组算符 比如 { body } 来共同的实现循环 <br>
     * 注意：for的evaluate 只返回 循环的指令结构,并不完成 数据运算。这就是 说他是 <br>
     * 指令算符的 原因，只定义/描述运算而不执行计算。<br>
     * 
     * 指令算符的名称使用 $name 表示 <br>
     * 
     * compose 和 evaluate 连个函数是 进行 自定义算符 必须实现的 函数
     * 
     * @author gbench
     * 
     * @param <T>
     */
    static class For<T> extends UnaryOp<T> {

        public For(final T t) {
            super("for", t);
        }

        public For<T> duplicate() {
            return new For<>(this._2._1);
        }

        /**
         * compose 和 evaluate 连个函数是 进行 自定义算符 必须实现的 函数 <br>
         * 根据 argsEval 计算的参数 进行 算符求值
         */
        @Override
        public Object evaluate(final Map<String, Object> bindings) {
            final var root = PACK(this._2._1); // 根节点，参数二叉树的根节点。
            final var nodes = Comma.flatten(root); // for 是四元运算符

            if (nodes.size() < 3) { // 参数数量检测
                try {
                    throw new Exception("for算符的参数结构异常:\n" + Node.PACK(this).dumpAST());
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return null;
            } else { // 合法进行分支选择
                final var loop_init = nodes.get(0); // 循环初始化
                final var loop_condition = nodes.get(1); // 循环条件检测
                final var loop_increment = nodes.get(2); // 循环递进
                
                return IRecord.rb("$name,loop_init,loop_condition,loop_increment")
                        .get("for",loop_init,loop_condition,loop_increment); // 返回记录格式
            } // if
        }

        /**
         * compose 和 evaluate 连个函数是 进行 自定义算符 必须实现的 函数<br>
         * 固定返回 自定义函数对象本身 <br>
         */
        @Override
        public <X> For<X> compose(final X x) {
            return new For<>(x);
        }

    }
    
    /**
     * 自定义 二元算符：分组算符 <br>
     * 
     * 分组算符 需要 与 前面的 指令算符 进行配合 来 共同的 计算出一个 特定的 结果值 <br>
     * 基本模式 是 instruction {分组指令} 例如: <br>
     * for(i:0,i<10,i:i+1){sum:sum+x[i]; z:sum} <br>
     * 
     * compose 和 evaluate 连个函数是 进行 自定义算符 必须实现的 函数
     * 
     * 
     * @author gbench
     * 
     * @param <T>
     */
    static class Group<T, U> extends BinaryOp<T, U> {
    
        public Group(final T t, U u) {
            super("{", TUP2(t, u));
        }
    
        @Override
        public Group<T, U> duplicate() {
            return new Group<>(this._2._1, this._2._2());
        }
    
        /**
         * compose 和 evaluate 连个函数是 进行 自定义算符 必须实现的 函数 <br>
         * 根据 argsEval 计算的参数 进行 算符求值
         */
        @Override
        public Object evaluate(final Map<String, Object> bindings) {
            final var left = PACK(this._2._1).evaluate(bindings); // 指令参数 比如  for 的 循环配置
            final var body = PACK(this._2._2); //  指令执行体，比如 for的循环体
            
            if (left instanceof IRecord) { // 分组算符的 left 参数是一个 指令定义/描述结构
                final var defun = ((IRecord) left); // 提取指令信息, define function
                final var name = defun.str("$name"); // 提取指令算符名,指令算符的名称使用 $name 表示
                
                switch (name) { // 指令选择
                    case "for": { // for语句
                        final var loop_init = defun.get("loop_init", Node.class); // 循环初始化
                        final var loop_condition = defun.get("loop_condition", Node.class); // 循环条件检测
                        final var loop_increment = defun.get("loop_increment", Node.class); // 循环递进
                        final var nodes = flatten(";", body.getOp());
    
                        loop_init.eval(bindings);
                        while ((Boolean) loop_condition.evaluate(bindings)) {
                            nodes.forEach(node -> {
                                node.evaluate(bindings);
                            });// forEach
                            loop_increment.evaluate(bindings);
                        } // while
    
                        break;
                    } // case
    
                    default: {
                        // do nothing
                    } // default
                } // switch
            } // if
            
            return bindings; // 数据绑定信息
        }
    
        /**
         * compose 和 evaluate 连个函数是 进行 自定义算符 必须实现的 函数 <br>
         * 固定返回 自定义函数对象本身 <br>
         */
        @Override
        public <X, Y> Group<X, Y> compose(final X x, final Y y) {
            return new Group<>(x, y);
        }
    
    }

    public static <X,Y> Mul<X,Y> MUL(X x, Y y){
        return new Mul<>(x,y);
    }
    
    public static <X,Y> Add<X,Y> ADD(X x, Y y){
        return new Add<>(x,y);
    }
    
    public static <X> Transpose<X> TP(X x){
        return new Transpose<>(x);
    }
    
    public static <X,Y> Assign<X,Y> ASSIGN(X x,Y y){
        return new Assign<>(x,y);
    }
    
    public static <X,Y> Get<X,Y> GET(X x,Y y){
        return new Get<>(x,y);
    }
    
    public static <X> For<X> FOR(X x){
        return new For<>(x);
    }
    
    public static <X,Y> Group<X,Y> GROUP(X x,Y y){
        return new Group<>(x,y);
    }
    
    public static <X,Y> Join<X,Y> JOIN(X x,Y y){
        return new Join<>(x,y);
    }
    
    public static <X,Y> Lt<X,Y> LT(X x,Y y){
        return new Lt<>(x,y);
    }
    
    /**
     * 深度遍历一个二元算符并尝试扁平化参数
     * 
     * @param opName 算符名称
     * @param binaryOp 二元算符
     * @return 节点序列
     */
    public static List<Node> flatten(String opName,final BinaryOp<?, ?> binaryOp) {
        final var stack = new Stack<Node>(); // 深度遍历的工作堆栈
        final var nodes = new LinkedList<Node>(); // 提取 逗号表达式的参数项目，这是一个树形结构的深度遍历后可以得出参数列表
        
        stack.push(PACK(binaryOp)); // 根节点入栈
        while (!stack.empty()) { // 尝试对root 做深度遍历
            final var node = stack.pop(); // 提取数据节点
            if (node.getName().equals(opName)) { // 把逗号表达式进行深度遍历
                final var op = node.getOp(); // 转换成算符结构
                // 注意这是 先1后2，入栈，出栈的时候就是先2后1
                op.getArgsS().map(Node::PACK).forEach(stack::push); // 参数入栈
            } else { // 提取逗号表达式的节点作为参数项目
                nodes.addFirst(node); // 由于是先2后1的出栈顺序，因此遍历为了保证初始顺序，这里 采用addFirst 给予恢复。
            } // if
        } // while
        
        return nodes;
    }
    
    /**
     * 转换成双精度浮点数
     * 
     * @param obj 目标对象
     * @return 双精度浮点数
     */
    public static Double dbl(final Object obj) {
        return IRecord.obj2dbl().apply(obj);
    }
    
    /**
     * 矩阵乘法
     * 
     * @param lmx 左矩阵
     * @param rmx 右矩阵
     * @return 矩阵乘法
     */
    public static Matrix<Double> mmult(final Matrix<Double> lmx, final Matrix<Double> rmx) {
        // return lmx.mmult(rmx, (a, b) -> a * b, summarizingDouble(e -> e)).fmap(e -> e.getSum());
        return Stream.of(lmx,rmx).map(Matrix::cells).reduce(MatrixOps::mmult).map(Matrix::new).orElse(null);
    }

    /**
     * 数值矩阵的转化
     * 
     * @param mx
     * @return
     */
    public static Matrix<Double> dblcorece(final Matrix<?> mx) {
        return mx.fmap(IRecord.obj2dbl());
    }

    @Test
    public void foo() {
        
        final var engine = new AlgebraEngine();
        
        Stream.of(MUL(null, null), ADD(null, null), TP(null), ASSIGN(null,null)).forEach(engine::add);
        
        Stream.of(
            "a*b+a",
            "1.5+a*b*sin(x)+cos(x)"
        ).forEach(line -> {
            final var node = engine.analyze(line);
            println(node.dumpAST());
            
            final var vec = NVec.of(10, i -> i); // 基础向量
            final var mx = Matrix.of(10, 10, (i, j) -> i * 10 + j);
            
            final var session1 = REC("a", 1, "b", 5, "x", Math.PI / 6);
            final var session2 = REC("a", vec, "b", vec, "x", Math.PI / 6);
            final var session3 = REC("a", vec, "b", 2, "x", Math.PI / 6);
            final var session4 = REC("a", 2, "b", vec, "x", Math.PI / 6);
            final var session5 = REC("a", mx, "b", vec, "x", Math.PI / 6); // 矩阵乘法
            final var session6 = REC("a", mx, "b", mx, "x", Math.PI / 6); // 矩阵乘法
            final var session7 = REC("a", V(vec), "b", V(vec).tp(), "x", Math.PI / 6); // 矩阵乘法
            
            Stream.of(
                session1, session2, session3, session4, session5, session6,
                session7
            ).forEach(session -> {
                println("------------------------------------");
                println(session);
                println("------------------------------------");
                println(node.evaluate(session));
            }); // forEach session
        }); // forEach line
        
    }
    
    @Test
    public void bar() {
       
        final var engine = new AlgebraEngine();
        
        Stream.of(MUL(null, null), ADD(null, null), TP(null)).forEach(engine::add);

        final var vec = NVec.of(10, i -> i); // 基础向量
        final var mx = Matrix.of(10, 10, (i, j) -> i * 10 + j);

        final var session1 = REC("a", V(vec)); // 矩阵乘法
        final var session2 = REC("a", mx.toArray()); // 矩阵乘法
        
        Stream.of(session1, session2).forEach(session -> { // 矩阵的转置
            final var node = engine.analyze("t(a)").evaluate(session);
            println(node);
        }); // forEach session
    }
    
    /**
     * 提取算符的演示，这里使用 分组括号额功能。<br>
     * 有了 分组括号 其实 是可以表示 字符串数据 ，比如 'abc is book' 就可以 <br>
     * 表示为 (', (" ", (" ", abc, is), "book")) 这样的 表达式结构，<br>
     * 只不过 这里需要定义一个空格连接函数 " ",<br>
     * 一表示(" ","abc","def") 即 : "abc" " " "def" 的运算结果为 "abc def" <br>
     * 这里为了显示方便把 算符空格 加上了引号。<br>
     * 
     * 但是由于 AlgebraEngine 分析器 自动把 空格给过滤掉了，所以 上面的设计 在 不更改 <br>
     * AlgebraEngine 的 词法分析器的 tokenize 的时候 是 不能够试下的，这里 这是 在这里提一下而已。<br>
     * 告诉大家 可以 有这样的一种 字符串的 数据计算的 办法。<br>
     */
    @Test
    public void qux(){
        
        final var engine = new AlgebraEngine().addBrace("[]".split("")); // 添加分组括号，以辅助规约
        
        Stream.of(MUL(null, null), ADD(null, null), TP(null), ASSIGN(null, null), GET(null, null)).forEach(engine::add);
        
        final var session = REC(); // 创建会话变量
        final var node = engine.analyze("(x:1+(y:(z:2*3)/4))[x]+1*2-1"); // 可以通过赋值函数提取中间过程结果
        println(node.dumpAST());
        println("计算值",node.eval(session));
        println("查看计算的值",session);
    }

    /**
     * 指令+分组指令的演示
     */
    @Test
    public void quz(){
        
        final var engine = new AlgebraEngine(); // 添加分组括号，以辅助规约
        
        Stream.of(MUL(null, null), ADD(null, null), TP(null), ASSIGN(null, null), GET(null, null)
                ,FOR(null), GROUP(null, null), JOIN(null, null), LT(null, null)
        ).forEach(engine::add);
        
        Stream.of("[],{}".split(",")).map(e->e.split("")).forEach(engine::addBrace);
        
        final var node = engine.analyze("sum:0; for(i:0, i<10, i:i+1) { sum:sum+x[i]; z:sum } [z]");
        
        println("语法树结构:\n",node.dumpAST());
        println("计算结果:",node.evaluate("x",NVec.of(10,i->i+1)));
    }

}
